home *** CD-ROM | disk | FTP | other *** search
/ isnet Internet / Isnet Internet CD.iso / prog / hiz / 09 / 09.exe / adynware.exe / perl / lib / site / Date / DateCalcLib.pm < prev    next >
Encoding:
Perl POD Document  |  1999-12-28  |  25.6 KB  |  1,017 lines

  1.  
  2.  
  3. package Date::DateCalcLib;
  4.  
  5. use strict;
  6. use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
  7.  
  8. require Exporter;
  9.  
  10. @ISA = qw(Exporter);
  11.  
  12. @EXPORT = qw();
  13.  
  14. @EXPORT_OK = qw( nth_wday_of_month_year decode_date_us decode_date_eu
  15. year_month_day_offset parse_date easter_sunday calendar );
  16.  
  17. %EXPORT_TAGS = (all => [@EXPORT_OK]);
  18.  
  19. $VERSION = '3.2';
  20.  
  21. use Carp;
  22.  
  23. use Date::DateCalc qw(:all);
  24.  
  25. sub nth_wday_of_month_year
  26. {
  27.     croak "Usage: (\$year,\$mm,\$dd) = nth_wday_of_month_year(\$nth,\$wday,\$month,\$year);"
  28.       if (@_ != 4);
  29.  
  30.     my($nth,$wday,$month,$year) = @_;
  31.     my($first,$offset);
  32.     my($yy,$mm,$dd);
  33.  
  34.     return()
  35.       if (($nth < 1) || ($nth > 5) ||
  36.           ($wday < 1) || ($wday > 7) ||
  37.           ($month < 1) || ($month > 12) ||
  38.           ($year < 1));
  39.  
  40.     $first = day_of_week($year,$month,1);
  41.  
  42.     $offset = $wday - $first;
  43.     $offset += 7 if ($offset < 0);
  44.     $offset += --$nth * 7;
  45.  
  46.     return()
  47.       unless (($yy,$mm,$dd) = calc_new_date($year,$month,1,$offset));
  48.  
  49.     return()
  50.       if ($mm != $month);
  51.  
  52.     return($yy,$mm,$dd);
  53. }
  54.  
  55. sub decode_date_us
  56. {
  57.     croak "Usage: (\$year,\$mm,\$dd) = decode_date_us(\$date);"
  58.       if (@_ != 1);
  59.  
  60.     my($buffer) = @_;
  61.     my($yy,$mm,$dd,$len);
  62.  
  63.     if ($buffer =~ /^[^A-Za-z0-9]*  ([A-Za-z]+)  [^A-Za-z0-9]*  0*(\d+)  \D*$/x)
  64.     {
  65.         ($mm,$buffer) = ($1,$2);
  66.         $mm = decode_month($mm);
  67.         unless ($mm > 0)
  68.         {
  69.             return(); # can't decode month!
  70.         }
  71.         $len = length($buffer);
  72.         if    ($len == 2)
  73.         {
  74.             $dd = substr($buffer,0,1);
  75.             $yy = substr($buffer,1,1);
  76.         }
  77.         elsif ($len == 3)
  78.         {
  79.             $dd = substr($buffer,0,1);
  80.             $yy = substr($buffer,1,2);
  81.         }
  82.         elsif ($len == 4)
  83.         {
  84.             $dd = substr($buffer,0,2);
  85.             $yy = substr($buffer,2,2);
  86.         }
  87.         elsif ($len == 5)
  88.         {
  89.             $dd = substr($buffer,0,1);
  90.             $yy = substr($buffer,1,4);
  91.         }
  92.         elsif ($len == 6)
  93.         {
  94.             $dd = substr($buffer,0,2);
  95.             $yy = substr($buffer,2,4);
  96.         }
  97.         else { return(); } # wrong number of digits!
  98.     }
  99.     elsif ($buffer =~ /^[^A-Za-z0-9]*  ([A-Za-z]+)  [^A-Za-z0-9]*  (\d+)  \D+  (\d+)  \D*$/x)
  100.     {
  101.         ($mm,$dd,$yy) = ($1,$2,$3);
  102.         $mm = decode_month($mm);
  103.         unless ($mm > 0)
  104.         {
  105.             return(); # can't decode month!
  106.         }
  107.     }
  108.     elsif ($buffer =~ /^\D*  0*(\d+)  \D*$/x)
  109.     {
  110.         $buffer = $1;
  111.         $len = length($buffer);
  112.         if    ($len == 3)
  113.         {
  114.             $mm = substr($buffer,0,1);
  115.             $dd = substr($buffer,1,1);
  116.             $yy = substr($buffer,2,1);
  117.         }
  118.         elsif ($len == 4)
  119.         {
  120.             $mm = substr($buffer,0,1);
  121.             $dd = substr($buffer,1,1);
  122.             $yy = substr($buffer,2,2);
  123.         }
  124.         elsif ($len == 5)
  125.         {
  126.             $mm = substr($buffer,0,1);
  127.             $dd = substr($buffer,1,2);
  128.             $yy = substr($buffer,3,2);
  129.         }
  130.         elsif ($len == 6)
  131.         {
  132.             $mm = substr($buffer,0,2);
  133.             $dd = substr($buffer,2,2);
  134.             $yy = substr($buffer,4,2);
  135.         }
  136.         elsif ($len == 7)
  137.         {
  138.             $mm = substr($buffer,0,1);
  139.             $dd = substr($buffer,1,2);
  140.             $yy = substr($buffer,3,4);
  141.         }
  142.         elsif ($len == 8)
  143.         {
  144.             $mm = substr($buffer,0,2);
  145.             $dd = substr($buffer,2,2);
  146.             $yy = substr($buffer,4,4);
  147.         }
  148.         else { return(); } # wrong number of digits!
  149.     }
  150.     elsif ($buffer =~ /^\D*  (\d+)  \D+  (\d+)  \D+  (\d+)  \D*$/x)
  151.     {
  152.         ($mm,$dd,$yy) = ($1,$2,$3);
  153.     }
  154.     else { return(); } # no match at all!
  155.  
  156.     if ($yy < 100) { $yy += 1900; }
  157.  
  158.     if (check_date($yy,$mm,$dd))
  159.     {
  160.         return($yy,$mm,$dd);
  161.     }
  162.     else { return(); } # not a valid date!
  163. }
  164.  
  165. sub decode_date_eu
  166. {
  167.     croak "Usage: (\$year,\$mm,\$dd) = decode_date_eu(\$date);"
  168.       if (@_ != 1);
  169.  
  170.     my($buffer) = @_;
  171.     my($yy,$mm,$dd,$len);
  172.  
  173.     if ($buffer =~ /^\D*  (\d+)  [^A-Za-z0-9]*  ([A-Za-z]+)  [^A-Za-z0-9]*  (\d+)  \D*$/x)
  174.     {
  175.         ($dd,$mm,$yy) = ($1,$2,$3);
  176.         $mm = decode_month($mm);
  177.         unless ($mm > 0)
  178.         {
  179.             return(); # can't decode month!
  180.         }
  181.     }
  182.     elsif ($buffer =~ /^\D*  0*(\d+)  \D*$/x)
  183.     {
  184.         $buffer = $1;
  185.         $len = length($buffer);
  186.         if    ($len == 3)
  187.         {
  188.             $dd = substr($buffer,0,1);
  189.             $mm = substr($buffer,1,1);
  190.             $yy = substr($buffer,2,1);
  191.         }
  192.         elsif ($len == 4)
  193.         {
  194.             $dd = substr($buffer,0,1);
  195.             $mm = substr($buffer,1,1);
  196.             $yy = substr($buffer,2,2);
  197.         }
  198.         elsif ($len == 5)
  199.         {
  200.             $dd = substr($buffer,0,1);
  201.             $mm = substr($buffer,1,2);
  202.             $yy = substr($buffer,3,2);
  203.         }
  204.         elsif ($len == 6)
  205.         {
  206.             $dd = substr($buffer,0,2);
  207.             $mm = substr($buffer,2,2);
  208.             $yy = substr($buffer,4,2);
  209.         }
  210.         elsif ($len == 7)
  211.         {
  212.             $dd = substr($buffer,0,1);
  213.             $mm = substr($buffer,1,2);
  214.             $yy = substr($buffer,3,4);
  215.         }
  216.         elsif ($len == 8)
  217.         {
  218.             $dd = substr($buffer,0,2);
  219.             $mm = substr($buffer,2,2);
  220.             $yy = substr($buffer,4,4);
  221.         }
  222.         else { return(); } # wrong number of digits!
  223.     }
  224.     elsif ($buffer =~ /^\D*  (\d+)  \D+  (\d+)  \D+  (\d+)  \D*$/x)
  225.     {
  226.         ($dd,$mm,$yy) = ($1,$2,$3);
  227.     }
  228.     else { return(); } # no match at all!
  229.  
  230.     if ($yy < 100) { $yy += 1900; }
  231.  
  232.     if (check_date($yy,$mm,$dd))
  233.     {
  234.         return($yy,$mm,$dd);
  235.     }
  236.     else { return(); } # not a valid date!
  237. }
  238.  
  239. sub year_month_day_offset
  240. {
  241.     croak "Usage: (\$year,\$mm,\$dd) = year_month_day_offset(\$year,\$mm,\$dd,\$y_offs,\$m_offs,\$d_offs);"
  242.       if (@_ != 6);
  243.  
  244.     my($year,$mm,$dd,$y_offset,$m_offset,$d_offset) = @_;
  245.     my($y_diff);
  246.  
  247.     $year     = int($year);
  248.     $mm       = int($mm);
  249.     $dd       = int($dd);
  250.  
  251.     $y_offset = int($y_offset);
  252.     $m_offset = int($m_offset);
  253.     $d_offset = int($d_offset);
  254.  
  255.     return()
  256.       unless (check_date($year,$mm,$dd));
  257.  
  258.     if ($d_offset != 0)
  259.     {
  260.         return()
  261.           unless (($year,$mm,$dd) = calc_new_date($year,$mm,$dd,$d_offset));
  262.     }
  263.  
  264.     $y_diff = 0;
  265.  
  266.     if ($m_offset != 0)
  267.     {
  268.         $mm += --$m_offset;       # "--" because $mm is in the range 1..12
  269.  
  270.         $y_diff = int($mm / 12);
  271.         $mm -= $y_diff * 12;
  272.  
  273.         if ($mm < 0) { $mm += 12; $y_diff--; }
  274.  
  275.         $mm++;                    # shift $mm back into the range 1..12
  276.     }
  277.  
  278.     $year += $y_diff + $y_offset;
  279.  
  280.     if ($year > 0)
  281.     {
  282.         if (($dd == 29) && ($mm == 2) && (!leap($year))) { $dd = 1; $mm = 3; }
  283.         return($year,$mm,$dd);
  284.     }
  285.     else { return(); }
  286. }
  287.  
  288. sub parse_date
  289. {
  290.     croak "Usage: (\$year,\$mm,\$dd) = parse_date(\$date);"
  291.       if (@_ != 1);
  292.  
  293.     my($date) = @_;
  294.     my($yy,$mm,$dd);
  295.     unless ($date =~ /\b([JFMASOND][aepuco][nbrynlgptvc])\s+([0123]??\d)\b/)
  296.     {
  297.         return();
  298.     }
  299.     $mm = $1;
  300.     $dd = $2;
  301.     unless ($date =~ /\b(19\d\d|20\d\d)\b/)
  302.     {
  303.         return();
  304.     }
  305.     $yy = $1;
  306.     $mm = decode_month($mm);
  307.     unless ($mm > 0)
  308.     {
  309.         return();
  310.     }
  311.     unless (check_date($yy,$mm,$dd))
  312.     {
  313.         return();
  314.     }
  315.     return($yy,$mm,$dd);
  316. }
  317.  
  318. sub easter_sunday  #  Gauss'sche Regel (Gauss' Rule)
  319. {
  320.  
  321.  
  322.     croak "Usage: (\$year,\$mm,\$dd) = easter_sunday(\$year);"
  323.       if (@_ != 1);
  324.  
  325.     my($year) = @_;
  326.     my($a,$b,$c,$d,$e,$m,$n);
  327.     my($mm,$dd);
  328.  
  329.     return()
  330.       if (($year < 1583) || ($year > 2299));
  331.  
  332.     if    ($year < 1700) { $m = 22; $n = 2; }
  333.     elsif ($year < 1800) { $m = 23; $n = 3; }
  334.     elsif ($year < 1900) { $m = 23; $n = 4; }
  335.     elsif ($year < 2100) { $m = 24; $n = 5; }
  336.     elsif ($year < 2200) { $m = 24; $n = 6; }
  337.     else                 { $m = 25; $n = 0; }
  338.  
  339.     $a = $year % 19;
  340.     $b = $year % 4;
  341.     $c = $year % 7;
  342.     $d = (19 * $a + $m) % 30;
  343.     $e = (2 * $b + 4 * $c + 6 * $d + $n) % 7;
  344.     $dd = 22 + $d + $e;
  345.     $mm = 3;
  346.  
  347.     if ($dd > 31)
  348.     {
  349.         $dd -= 31;  #  $dd = $d + $e - 9;
  350.         $mm++;
  351.     }
  352.  
  353.     if (($dd == 26) && ($mm == 4))
  354.     { $dd = 19; }
  355.  
  356.     if (($dd == 25) && ($mm == 4) && ($d == 28) && ($e == 6) && ($a > 10))
  357.     { $dd = 18; }
  358.  
  359.     return($year,$mm,$dd);
  360. }
  361.  
  362.  
  363. sub calendar
  364. {
  365.     croak "Usage: \$string = calendar(\$year,\$month);"
  366.       if (@_ != 2);
  367.  
  368.     my($year,$month) = @_;
  369.     my($first,$last);
  370.     my($i,$j);
  371.     my($cal);
  372.  
  373.     return()
  374.       if (($month < 1) || ($month > 12) || ($year < 1));
  375.  
  376.     $cal = center((month_name_tab($month) . ' ' . $year), 27);
  377.     $cal .= "\nMon Tue Wed Thu Fri Sat Sun\n";
  378.  
  379.     $first = day_of_week($year,$month,1);
  380.     $last = days_in_month($year,$month);
  381.  
  382.     $j = $first - 1;
  383.  
  384.     $cal .= ('    ' x $j);
  385.  
  386.     for ( $i = 1; $i <= $last; $i++, $j++ )
  387.     {
  388.         if ($j >= 7)
  389.         {
  390.             $j = 0;
  391.             $cal .= "\n";
  392.         }
  393.         $cal .= sprintf(" %2d ", $i);
  394.     }
  395.     $cal .= "\n";
  396.     return($cal);
  397. }
  398.  
  399. sub center
  400. {
  401.     my($string,$width) = @_;
  402.     my($length,$left,$right);
  403.  
  404.     $length = length($string);
  405.     return($string) if ($length >= $width);
  406.     $length = $width - $length;
  407.     $left = int($length / 2);
  408.     $right = $length - $left;
  409.     return( (' ' x $left) . $string . (' ' x $right) );
  410. }
  411.  
  412. 1;
  413.  
  414. __END__
  415.  
  416. =head1 NAME
  417.  
  418. Date::DateCalcLib - Date Calculations Library
  419.  
  420. Library of useful date calculation functions
  421.  
  422. =head1 SYNOPSIS
  423.  
  424. =over 4
  425.  
  426. =item *
  427.  
  428. C<use Date::DateCalcLib qw( nth_wday_of_month_year>
  429. C<decode_date_us decode_date_eu year_month_day_offset>
  430. C<parse_date easter_sunday calendar );>
  431.  
  432. =item *
  433.  
  434. C<use Date::DateCalcLib qw(:all);>
  435.  
  436. =item *
  437.  
  438. C<($year,$mm,$dd) = nth_wday_of_month_year($nth,$wday,$month,$year);>
  439.  
  440. =item *
  441.  
  442. C<($year,$mm,$dd) = decode_date_us($date);>
  443.  
  444. =item *
  445.  
  446. C<($year,$mm,$dd) = decode_date_eu($date);>
  447.  
  448. =item *
  449.  
  450. C<($year,$mm,$dd) = year_month_day_offset($year,$mm,$dd,$y_offs,$m_offs,$d_offs);>
  451.  
  452. =item *
  453.  
  454. C<($year,$mm,$dd) = parse_date(`/bin/date`);>
  455.  
  456. =item *
  457.  
  458. C<($year,$mm,$dd) = easter_sunday($year);>
  459.  
  460. =item *
  461.  
  462. C<$string = calendar($year,$month);>
  463.  
  464. =back
  465.  
  466. =head1 DESCRIPTION
  467.  
  468. This module expands the functionality of the "Date::DateCalc" module
  469. (see L<Date::DateCalc(3)> for more details), which is intended to be
  470. a rather basic set of tools, with functions for various special tasks
  471. like:
  472.  
  473. =over 4
  474.  
  475. =item *
  476.  
  477. calculating the n-th weekday for a given month and year
  478.  
  479. =item *
  480.  
  481. parsing dates in U.S. american and european format
  482.  
  483. =item *
  484.  
  485. calculating a new date with a year, month and/or day offset
  486.  
  487. =item *
  488.  
  489. parsing the current date or the submission date of an e-mail message
  490.  
  491. =item *
  492.  
  493. calculating easter sunday and all the related christian feast days
  494.  
  495. =item *
  496.  
  497. printing a calendar for a given month and year
  498.  
  499. =back
  500.  
  501. For a detailed description of each function, see below:
  502.  
  503. =over 4
  504.  
  505. =item *
  506.  
  507. C<use Date::DateCalcLib qw( nth_wday_of_month_year>
  508. C<decode_date_us decode_date_eu year_month_day_offset>
  509. C<parse_date easter_sunday calendar );>
  510.  
  511. Use this statement to make the functions of this module
  512. available in your module or script.
  513.  
  514. You can also use any subset of the functions listed above
  515. that you like by only including the names of the functions
  516. you actually need between the parentheses of the "qw()"
  517. operator above.
  518.  
  519. =item *
  520.  
  521. C<use Date::DateCalcLib qw(:all);>
  522.  
  523. Alternate and simpler way of importing ALL the functions
  524. exported by this module into your module or script.
  525.  
  526. =item *
  527.  
  528. C<($year,$mm,$dd) = nth_wday_of_month_year($nth,$wday,$month,$year);>
  529.  
  530. This function calculates the n-th weekday for a given month and year,
  531. for example the 3rd Thursday of a given month and year.
  532.  
  533. "C<$nth>" must be in the range 1 to 5 (for "the first" to "the fifth"),
  534. "C<$wday>" must be in the range 1 to 7 (1 = Monday, 7 = Sunday),
  535. "C<$month>" must (of course) be in the range 1 to 12 and "C<$year>"
  536. must be greater than zero.
  537.  
  538. The function returns an empty list if any of its parameters is illegal
  539. or if the requested date cannot be calculated (for instance, if there
  540. is no fifth "C<$wday>" in the given month and year!).
  541.  
  542. Example:
  543.  
  544. Suppose you have a meeting (of some user group, for instance) in regular
  545. intervals, let's say the first Friday of each month, and that you want to
  546. send a mail to all members saying: "Remember: Tomorrow is our user group's
  547. meeting!" on the day before.
  548.  
  549. Given the current date, you would go about this as follows:
  550.  
  551. Convert the current date into days using the function "calc_days()"
  552. of the "Date::DateCalc" module. We'll refer to this number as "the
  553. number of days of the current date" below.
  554.  
  555. Calculate the first Friday of the current month.
  556.  
  557. Convert the resulting date into days using the function "calc_days()"
  558. of the "Date::DateCalc" module.
  559.  
  560. See if the number of days of the current date *plus one* is the same
  561. as the number of days of the first Friday of the current month.
  562.  
  563. If so, send your mail!
  564.  
  565. If not, calculate the first Friday of the NEXT month (beware: if the
  566. month is equal to 12, you need to "wrap" it back to 1 and to increment
  567. the year number!).
  568.  
  569. (This is necessary because the first Friday of any given month could
  570. fall on the first day of that month, which means that the day before
  571. that (when you want to send your mail!) is in the PREVIOUS month!)
  572.  
  573. Convert the resulting date into days using the function "calc_days()"
  574. of the "Date::DateCalc" module.
  575.  
  576. See if the number of days of the current date *plus one* is the same
  577. as the number of days of the first Friday of the next month.
  578.  
  579. If so, send your mail!
  580.  
  581. If not, you're done for today!
  582.  
  583. (On a UNIX system, you would normally use a "cron" job running once
  584. every day to automatically carry out these calculations and to send
  585. the reminder mail.)
  586.  
  587. =item *
  588.  
  589. C<($year,$mm,$dd) = decode_date_us($date);>
  590.  
  591. Using this function, you can parse dates in almost any format,
  592. provided the date is given as "month - day - year".
  593.  
  594. (To decode dates in european format, i.e., dates given as
  595. "day - month - year", see the function "decode_date_eu()"
  596. in this module or the function "decode_date()" in the
  597. "Date::DateCalc" module.)
  598.  
  599. The day and the year must be given as numbers, the month may be
  600. specified either by a number or its name in English (however,
  601. only up to the 3 first characters are compared, any extra
  602. characters are ignored). The latter comparison is carried out
  603. in a case-insensitive manner.
  604.  
  605. If they uniquely identify the month, one or two letters are
  606. sufficient (e.g., "s" for september or "ja" for january).
  607.  
  608. The year may be abbreviated as well, for instance "97" instead
  609. of "1997". (Year numbers below 100 are incremented by 1900.)
  610.  
  611. Note that leading zeros are ignored for all numeric values
  612. (= contiguous strings of digits).
  613.  
  614. If the month given in the input string isn't numeric, any number of
  615. non-alphanumeric characters (i.e., all characters NOT in [A-Za-z0-9])
  616. may precede and follow the month, and any number of non-digits (i.e.,
  617. all characters NOT in [0-9]) may precede and follow the year.
  618.  
  619. If separating non-digits between the day and year are missing, the
  620. string of digits following the month is automatically mapped to the
  621. day and year depending on its length, as intuitively as possible, as
  622. follows:
  623.  
  624.         Length:        Mapping:
  625.           2              dy
  626.           3              dyy
  627.           4              ddyy
  628.           5              dyyyy
  629.           6              ddyyyy
  630.  
  631. If the month given in the input string is numeric, any number of
  632. non-digits may precede the month, separate the month from the day
  633. and the day from the year, and follow the year.
  634.  
  635. If separating non-digits are missing, the string of digits contained
  636. in the input string is automatically mapped to the month, day and year
  637. depending on its length, as intuitively as possible, as follows:
  638.  
  639.         Length:        Mapping:
  640.           3              mdy
  641.           4              mdyy
  642.           5              mddyy
  643.           6              mmddyy
  644.           7              mddyyyy
  645.           8              mmddyyyy
  646.  
  647. Example:
  648.  
  649. All the following strings will be recognized as "January 3rd 1964":
  650.  
  651.               1 3 64
  652.               1.3.64
  653.              01.03.64
  654.              01/03/64
  655.             Jan 3 1964
  656.          January 3rd, 1964
  657.             Jan 3. '64
  658.              Jan-3-64
  659.              Jan3.1964
  660.                ja364
  661.                1364
  662.  
  663. If no valid date can be derived from the input string, the function
  664. returns an empty list.
  665.  
  666. =item *
  667.  
  668. C<($year,$mm,$dd) = decode_date_eu($date);>
  669.  
  670. Using this function, you can parse dates in almost any format,
  671. provided the date is given as "day - month - year".
  672.  
  673. (To decode dates in U.S. american format, i.e., dates given
  674. as "month - day - year", see the function "decode_date_us()"
  675. in this module.)
  676.  
  677. The day and the year must be given as numbers, the month may be
  678. specified either by a number or its name in English (however,
  679. only up to the 3 first characters are compared, any extra
  680. characters are ignored). The latter comparison is carried out
  681. in a case-insensitive manner.
  682.  
  683. If they uniquely identify the month, one or two letters are
  684. sufficient (e.g., "s" for september or "ja" for january).
  685.  
  686. The year may be abbreviated as well, for instance "97" instead
  687. of "1997". (Year numbers below 100 are incremented by 1900.)
  688.  
  689. Note that this function is a little more flexible than the function
  690. "decode_date()" in the "Date::DateCalc" module since it allows any
  691. number of leading zeros for numeric values and any number of letters
  692. for the name of the month.
  693.  
  694. If the month given in the input string isn't numeric, any number of
  695. non-alphanumeric characters (i.e., all characters NOT in [A-Za-z0-9])
  696. may precede and follow the month (separating it from the day and the
  697. year), and any number of non-digits (i.e., all characters NOT in [0-9])
  698. may precede the day and follow the year.
  699.  
  700. If the month given in the input string is numeric, any number of
  701. non-digits may precede the day, separate the day from the month
  702. and the month from the year, and follow the year.
  703.  
  704. In the latter case, if separating non-digits are missing, the string
  705. of digits contained in the input string is automatically mapped to the
  706. day, month and year depending on its length, as intuitively as possible,
  707. as follows:
  708.  
  709.         Length:        Mapping:
  710.           3              dmy
  711.           4              dmyy
  712.           5              dmmyy
  713.           6              ddmmyy
  714.           7              dmmyyyy
  715.           8              ddmmyyyy
  716.  
  717. Example:
  718.  
  719. All the following strings will be recognized as "January 3rd 1964":
  720.  
  721.               3.1.64
  722.               3 1 64
  723.              03.01.64
  724.              03/01/64
  725.             3. Jan 1964
  726.           3 January 1964
  727.             3. Jan '64
  728.              03-Jan-64
  729.              3.Jan1964
  730.               3Jan64
  731.                3ja64
  732.                3164
  733.  
  734. If no valid date can be derived from the input string, the function
  735. returns an empty list.
  736.  
  737. =item *
  738.  
  739. C<($year,$mm,$dd) = year_month_day_offset($year,$mm,$dd,$y_offs,$m_offs,$d_offs);>
  740.  
  741. Many people have asked for a function to calculate a new date, starting
  742. with a given date and a year, month and/or day offset. So here it is!
  743.  
  744. Note that all parameters must be integers.
  745.  
  746. The function ensures this by applying the "int()" function to every
  747. parameter.
  748.  
  749. An empty list is returned if the given date or any (intermediate or
  750. final) result is invalid.
  751.  
  752. Note that the day offset is added first using the "calc_new_date()"
  753. function of the "Date::DateCalc" module (see L<Date::DateCalc(3)>).
  754.  
  755. Beware that an empty list is returned if this intermediate result
  756. is not a valid date!
  757.  
  758. After this, the month offset is added and finally the year offset
  759. (with a possible carry over from the month) is added.
  760.  
  761. Note that all three offsets may have any (integer) value (provided
  762. that all (intermediate or final) results are valid dates) and any
  763. sign (independently from each other!).
  764.  
  765. If the final result happens to be the 29th of February in a non-leap
  766. year, it is substituted by the 1st of March.
  767.  
  768. BEWARE that because the three offsets are always applied in the
  769. same order, and also because of the substitution mentioned above,
  770. the transformation calculated by this function is NOT REVERSIBLE,
  771. in general!
  772.  
  773. (Unlike the "calc_new_date()" function of the "Date::DateCalc" module!)
  774.  
  775. I.e.,
  776.  
  777.     ($year,$mm,$dd) =
  778.     year_month_day_offset(
  779.     year_month_day_offset($year,$mm,$dd, $y_offs,$m_offs,$d_offs),
  780.     -$y_offs,-$m_offs,-$d_offs);
  781.  
  782. will not, in general, return the original date!
  783.  
  784. In the formula above, in order to reverse the effect of the first call
  785. to "year_month_day_offset()", the offsets do not only need to have the
  786. opposite sign, but they would also need to be applied in reverse order
  787. in the second call to "year_month_day_offset()"!
  788.  
  789. =item *
  790.  
  791. C<($year,$mm,$dd) = parse_date($date);>
  792.  
  793. This function is a (special!) relative of the "decode_date_us()" and
  794. "decode_date_eu()" function.
  795.  
  796. In contrast to the "decode_date_us()" and "decode_date_eu()" function,
  797. however, the month is required to be a three-letter abbreviation of
  798. the month's name (in English).
  799.  
  800. Moreover, the month's name is required to be followed by the day's number,
  801. separated by whitespace.
  802.  
  803. Another restriction is that year numbers must lie in the range 1900 to 2099.
  804.  
  805. In compensation, the year number may come before or after the month/day
  806. pair.
  807.  
  808. This function is especially designed to parse dates returned by the UNIX
  809. "date" command:
  810.  
  811. =back
  812.  
  813. =over 4
  814.  
  815. =item
  816.  
  817. C<-   >Parse today's date:
  818.  
  819.     ($year,$mm,$dd) = parse_date(`/bin/date`);
  820.  
  821. =item
  822.  
  823. C<-   >Parse date of submission of an e-mail:
  824.  
  825.     while (<MAIL>)
  826.     {
  827.         if (/^From \S/)
  828.         {
  829.             ($year,$mm,$dd) = parse_date($_);
  830.             ...
  831.         }
  832.         ...
  833.     }
  834.  
  835. =item
  836.  
  837. The function returns an empty list if it can't extract a valid date
  838. from the input string.
  839.  
  840. =back
  841.  
  842. =over 4
  843.  
  844. =item *
  845.  
  846. C<($year,$mm,$dd) = easter_sunday($year);>
  847.  
  848. Calculates the date of easter sunday for years in the range 1583 to 2299
  849. using Gauss' Rule.
  850.  
  851. Returns an empty list for all arguments outside this range.
  852.  
  853. Other christian feast days depend on easter sunday and can be calculated
  854. using the function "calc_new_date()" of the "Date::DateCalc" module (see
  855. L<Date::DateCalc(3)> for more info) as follows:
  856.  
  857. =back
  858.  
  859. =over 4
  860.  
  861. =item
  862.  
  863. C<*   >Easter Sunday - 48
  864.  
  865.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),-48);
  866.  
  867.     Carnival Monday / Rosenmontag / Veille du Mardi Gras
  868.  
  869. =item
  870.  
  871. C<*   >Easter Sunday - 47
  872.  
  873.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),-47);
  874.  
  875.     Mardi Gras / Faschingsdienstag, Karnevalsdienstag / Mardi Gras
  876.  
  877. =item
  878.  
  879. C<*   >Easter Sunday - 46
  880.  
  881.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),-46);
  882.  
  883.     Ash Wednesday / Aschermittwoch / Mercredi des Cendres
  884.  
  885. =item
  886.  
  887. C<*   >Easter Sunday - 7
  888.  
  889.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),-7);
  890.  
  891.     Palm Sunday / Palmsonntag / Dimanche des Rameaux
  892.  
  893. =item
  894.  
  895. C<*   >Easter Sunday - 2
  896.  
  897.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),-2);
  898.  
  899.     Easter Friday / Karfreitag / Vendredi Saint
  900.  
  901. =item
  902.  
  903. C<*   >Easter Sunday - 1
  904.  
  905.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),-1);
  906.  
  907.     Easter Saturday / Ostersamstag / Samedi de Paques
  908.  
  909. =item
  910.  
  911. C<*   >Easter Sunday + 1
  912.  
  913.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),1);
  914.  
  915.     Easter Monday / Ostermontag / Lundi de Paques
  916.  
  917. =item
  918.  
  919. C<*   >Easter Sunday + 39
  920.  
  921.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),39);
  922.  
  923.     Ascension of Christ / Christi Himmelfahrt / Ascension
  924.  
  925. =item
  926.  
  927. C<*   >Easter Sunday + 49
  928.  
  929.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),49);
  930.  
  931.     Whitsunday / Pfingstsonntag / Dimanche de Pentecote
  932.  
  933. =item
  934.  
  935. C<*   >Easter Sunday + 50
  936.  
  937.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),50);
  938.  
  939.     Whitmonday / Pfingstmontag / Lundi de Pentecote
  940.  
  941. =item
  942.  
  943. C<*   >Easter Sunday + 60
  944.  
  945.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),60);
  946.  
  947.     Feast of Corpus Christi / Fronleichnam / Fete-Dieu
  948.  
  949. =back
  950.  
  951. =over 4
  952.  
  953. =item
  954.  
  955. For more information about easter sunday and how to calculate it,
  956. see also on USENET in news.answers
  957.  
  958.     Calendar FAQ, v. 1.6 (modified 26 Dec 1996) Part 1/3
  959.     Calendar FAQ, v. 1.6 (modified 26 Dec 1996) Part 2/3
  960.     Calendar FAQ, v. 1.6 (modified 26 Dec 1996) Part 3/3
  961.  
  962. or
  963.  
  964.     http://www.math.uio.no/faq/calendars/faq.html
  965.  
  966. or
  967.  
  968.     http://www.pip.dknet.dk/~pip10160/calendar.html
  969.  
  970. All authored by
  971.  
  972.     Claus Tondering <c-t@pip.dknet.dk>
  973.  
  974. =back
  975.  
  976. =over 4
  977.  
  978. =item *
  979.  
  980. C<$string = calendar($year,$month);>
  981.  
  982. This function returns a string containing a calendar for the given
  983. month and year (which looks pretty much like the output of the UNIX
  984. "cal" command).
  985.  
  986. The calendar is not printed directly but rather returned as a string
  987. in order to make post-processing possible, i.e., like staggering multiple
  988. month calendars together on one page to produce a calendar of a complete
  989. year, or transforming the day numbers into hyperlinks for incorporation
  990. of the calendar (with clickable day numbers) into an HTML page.
  991.  
  992. The function returns an empty list if the given month or year is invalid.
  993.  
  994. =back
  995.  
  996. =head1 SEE ALSO
  997.  
  998. Date::DateCalc(3).
  999.  
  1000. =head1 VERSION
  1001.  
  1002. This man page documents "Date::DateCalcLib" version 3.2.
  1003.  
  1004. =head1 AUTHOR
  1005.  
  1006. Steffen Beyer <sb@sdm.de>.
  1007.  
  1008. =head1 COPYRIGHT
  1009.  
  1010. Copyright (c) 1997 by Steffen Beyer. All rights reserved.
  1011.  
  1012. =head1 LICENSE
  1013.  
  1014. This package is free software; you can redistribute it
  1015. and/or modify it under the same terms as Perl itself.
  1016.  
  1017.